package znet

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net"
	"sync"
	"time"
	"zinx-tianjing-study/util"
	"zinx-tianjing-study/ziface"
)

var (
	ErrConnectionClosed = errors.New("connection is closed")
	ErrWriteTimeout     = errors.New("write timeout")
	ErrReadTimeout      = errors.New("read timeout")
)

type Connection struct {
	sync.RWMutex
	Server   ziface.IServer
	Conn     *net.TCPConn
	ConnID   uint32
	isClosed bool

	ctx        context.Context
	cancelFunc context.CancelFunc

	// 消息通道
	msgChan  chan []byte
	ExitChan chan bool

	// 心跳相关
	heartbeat     time.Duration
	lastHeartbeat time.Time

	MessageHandle ziface.IMessageHandle
}

func (c *Connection) StartWriter() {
	fmt.Printf("[Writer Goroutine is running...] ConnID=%d\n", c.ConnID)
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Writer panic: %v\n", err)
		}
		fmt.Printf("ConnID=%d Writer exit, remote addr is %s\n", c.ConnID, c.RemoteAddr().String())
	}()

	for {
		select {
		case data := <-c.msgChan:
			if err := c.writeWithTimeout(data); err != nil {
				fmt.Printf("Send msg error: %v\n", err)
				return
			}
		case <-c.ctx.Done():
			return
		}
	}
}

func (c *Connection) writeWithTimeout(data []byte) error {
	if len(data) == 0 {
		return nil
	}

	writeTimeout := time.Duration(util.GlobalObject.WriteTimeout) * time.Second
	c.Conn.SetWriteDeadline(time.Now().Add(writeTimeout))
	_, err := c.Conn.Write(data)
	c.Conn.SetWriteDeadline(time.Time{}) // 清除写超时
	return err
}

func (c *Connection) StartReader() {
	fmt.Printf("[Reader Goroutine is running...] ConnID=%d\n", c.ConnID)
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("Reader panic: %v\n", err)
		}
		fmt.Printf("ConnID=%d Reader exit, remote addr is %s\n", c.ConnID, c.RemoteAddr().String())
		c.Stop()
	}()

	for {
		select {
		case <-c.ctx.Done():
			return
		default:
			if err := c.readMsgHandle(); err != nil {
				fmt.Printf("Read error: %v\n", err)
				return
			}
		}
	}
}

func (c *Connection) readMsgHandle() error {
	dp := GetDataPack()
	headData := make([]byte, dp.GetHeadLen())

	// 设置读取超时
	readTimeout := time.Duration(util.GlobalObject.ReadTimeout) * time.Second
	c.Conn.SetReadDeadline(time.Now().Add(readTimeout))
	if _, err := io.ReadFull(c.GetTCPConnection(), headData); err != nil {
		return fmt.Errorf("read msg head error: %w", err)
	}
	c.Conn.SetReadDeadline(time.Time{}) // 清除读超时

	msg, err := dp.UnPack(headData)
	if err != nil {
		return fmt.Errorf("unpack error: %w", err)
	}

	// 检查消息大小是否超过限制
	if msg.GetDataLen() > util.GlobalObject.MaxMsgSize {
		return fmt.Errorf("message size %d exceeds limit %d", msg.GetDataLen(), util.GlobalObject.MaxMsgSize)
	}

	if msg.GetDataLen() > 0 {
		data := make([]byte, msg.GetDataLen())
		if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil {
			return fmt.Errorf("read msg data error: %w", err)
		}
		msg.SetData(data)
	}

	req := &Request{
		coon: c,
		msg:  msg,
	}

	c.updateHeartbeat() // 更新心跳时间

	// 提交到 WorkerPool 处理
	if mh, ok := c.MessageHandle.(*MessageHandle); ok && mh.WorkerPoolSize > 0 {
		mh.SubmitTask(req)
	} else {
		go c.MessageHandle.DoMessageHandle(req)
	}

	return nil
}

func (c *Connection) Start() {
	c.Lock()
	defer c.Unlock()

	if c.isClosed {
		return
	}

	fmt.Printf("Connection starting... ConnID=%d\n", c.ConnID)

	// 启动心跳检测
	go c.heartbeatChecker()

	// 启动读写业务
	go c.StartReader()
	go c.StartWriter()

	// 执行钩子函数
	c.Server.CallOnConnStart(c)
}

func (c *Connection) Stop() {
	c.Lock()
	defer c.Unlock()

	if c.isClosed {
		return
	}

	fmt.Printf("Connection stopping... ConnID=%d\n", c.ConnID)

	// 调用钩子函数
	c.Server.CallOnConnStop(c)

	// 关闭socket连接
	c.Conn.Close()

	// 通知其他goroutine退出
	c.cancelFunc()

	// 将连接从连接管理器中移除
	c.Server.GetConnManger().Remove(c)

	// 关闭管道
	close(c.ExitChan)
	close(c.msgChan)

	c.isClosed = true
}

func (c *Connection) heartbeatChecker() {
	ticker := time.NewTicker(c.heartbeat / 2)
	defer ticker.Stop()

	for {
		select {
		case <-c.ctx.Done():
			return
		case <-ticker.C:
			if time.Since(c.lastHeartbeat) > c.heartbeat {
				fmt.Printf("Connection heartbeat timeout, ConnID=%d\n", c.ConnID)
				c.Stop()
				return
			}
		}
	}
}

func (c *Connection) updateHeartbeat() {
	c.Lock()
	c.lastHeartbeat = time.Now()
	c.Unlock()
}

func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

func (c *Connection) GetConnectionID() uint32 {
	return c.ConnID
}

func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

func (c *Connection) Send(id uint32, data []byte) error {
	c.RLock()
	if c.isClosed {
		c.RUnlock()
		return ErrConnectionClosed
	}
	c.RUnlock()

	dp := GetDataPack()
	binaryMsg, err := dp.Pack(NewMessage(id, data))
	if err != nil {
		return fmt.Errorf("pack data error: %w", err)
	}

	// 使用select避免阻塞
	select {
	case c.msgChan <- binaryMsg:
		return nil
	case <-time.After(time.Second * 5):
		return ErrWriteTimeout
	}
}

// 初始化连接
func NewConnection(server ziface.IServer, conn *net.TCPConn, connId uint32, msgHandle ziface.IMessageHandle) ziface.IConnection {
	c := &Connection{
		Server:        server,
		Conn:          conn,
		ConnID:        connId,
		isClosed:      false,
		MessageHandle: msgHandle,
		msgChan:       make(chan []byte, util.GlobalObject.MaxPackageSize),
		ExitChan:      make(chan bool, 1),
		heartbeat:     time.Duration(util.GlobalObject.HeartbeatTimeout) * time.Second,
		lastHeartbeat: time.Now(),
	}

	// 创建上下文和取消函数
	c.ctx, c.cancelFunc = context.WithCancel(context.Background())

	// 设置TCP连接属性
	c.Conn.SetNoDelay(true)
	c.Conn.SetKeepAlive(true)
	c.Conn.SetKeepAlivePeriod(30 * time.Second)

	// 添加到连接管理器
	c.Server.GetConnManger().Add(c)

	return c
}
